www.gusucode.com > VC++ RingSDK界面库 > VC++ RingSDK界面库/code/libsrc/ringdows/ringtreedir.cpp

    /**********************************************************************
//
//
//        ##########                          ######  #########   # ######    #
//      #############                      ########### ######### #########  ###
//     ######## # ###  ##                 ############# ##    ## #####  # ####
//     ####  ##    ## ###                 ###     ### # #      #####   #####
//          #     ###  #            #     ##       ##  ##      ##     ###
//         ## ###### ##      ##  ####    ####          #       #     ##
//       #########  ###  ## ### #######   ######      ##      ##    ###
//      ######      ##  ######  ##  ##       ####     #      ##     ####
//     #######     ##   ###### ##  ###          ##   ##     ###    ######
//     #########   ##  ###### ## ######         ### ##    ###      #  #####
//    ##    ###### ####### ### #### ##  ## #######  ########      ##    ####
//    ##      #### ###  #  ### ### ##  ##########   ######       ##      ####
//   ##         ##                ##   #########    ####         #         ##
//               #              ###
//                              ##
//                             ###
//                             ##
//
//
//							临风程序界面类库 ringdows.lib
//作者:临风
//
//版本:1.0
//
//声明:本类库可以自由使用而不须对作者作出任何回报,但作者希望能得到
//		  你的鼓励和支持。你可以对类库源码作出修改和改进,但希望你能在
//		  修改的同时给作者一份同样的副本。
//		  本类库不得用于任何商业用途,如确实需要,请与作者联系。
//
//e-mail:ringphone@sina.com
//
//原文件名:ringtreedir.cpp
//
//说明:文件夹列表树型控件控制
//
**********************************************************************/
#define MAKE_SELF_LIB
#include "ringdows.h"

typedef struct tagTVItemData
{
	LPITEMIDLIST	lpi;
	LPSHELLFOLDER	lpsfParent;
	LPITEMIDLIST	lpifq;
}TVITEMDATA,*LPTVITEMDATA;

BOOL RingDirTree::Create(UINT uId,int x,int y,int width,int height)
{
	if(RingTree::Create(WS_VISIBLE|WS_CHILD|TVS_HASLINES|TVS_LINESATROOT|
									TVS_HASBUTTONS|TVS_SHOWSELALWAYS/*|WS_BORDER/*CCS_NOPARENTALIGN|
									CCS_NODIVIDER|CCS_NORESIZE|*/,WS_EX_STATICEDGE,NULL,uId,x,y,width,height))
	{
		InitImageList();
		return TRUE;
	}
	else
		return FALSE;
}

BOOL RingDirTree::Create(DWORD dwStyle,DWORD dwExStyle,LPCTSTR szInitText,UINT uId,int x,int y,int width,int height)
{
	if(RingTree::Create(dwStyle|WS_VISIBLE|WS_CHILD|TVS_HASLINES|TVS_LINESATROOT|
									TVS_HASBUTTONS|TVS_SHOWSELALWAYS/*|CCS_NOPARENTALIGN|
									CCS_NODIVIDER|CCS_NORESIZE*/,dwExStyle,szInitText,
									uId,x,y,width,height))
	{
		InitImageList();
		return TRUE;
	}
	else
		return FALSE;
}

void RingDirTree::InitImageList()
{	
	if(m_hImage == NULL)
	{
		SHFILEINFO  sfi;
		m_hImage = (HIMAGELIST)SHGetFileInfo((LPCSTR)"C:\\",0,&sfi,sizeof(SHFILEINFO),
															SHGFI_SYSICONINDEX|SHGFI_ICON|SHGFI_SMALLICON);
	
  		if(m_hImage)
			TreeView_SetImageList(m_hWnd,m_hImage,0);
	}	
}

BOOL RingDirTree::Attach(HWND hWnd)
{
	BOOL bOK = RingControls::Attach(hWnd);

	if(bOK)
	{
		ReplaceStyle(GetStyle(),WS_VISIBLE|WS_CHILD|TVS_HASLINES|TVS_LINESATROOT|
										TVS_HASBUTTONS|TVS_SHOWSELALWAYS|CCS_NOPARENTALIGN);
		InitImageList();
	}
	return bOK;
}

int CALLBACK RingDirTree::SortCBProc(LPARAM lparam1,LPARAM lparam2,LPARAM lparamSort)
{
	LPTVITEMDATA lptvid1 = (LPTVITEMDATA)lparam1;
	LPTVITEMDATA lptvid2 = (LPTVITEMDATA)lparam2;
	HRESULT hr;
	
	hr = lptvid1->lpsfParent->CompareIDs(0,lptvid1->lpi,lptvid2->lpi);
	
	if (FAILED(hr))
		return 0;
	
	return (short)SCODE_CODE(GetScode(hr));
}

BOOL RingDirTree::ListDir()
{
	HRESULT	hr;
	BOOL bOK = FALSE;
	LPSHELLFOLDER lpsf = NULL;//IShellFolder 接口指针

	hr = SHGetDesktopFolder(&lpsf);

	if(SUCCEEDED(hr))
	{
		Clear();		
		FillTreeView(lpsf,NULL,TVI_ROOT);
		//SortChildren(TVI_ROOT,SortCBProc);
      Expand(GetRoot());
      Select(GetRoot());
      bOK = TRUE;
	}
   
	if(lpsf)
		lpsf->Release();

	return bOK;
}

LRESULT RingDirTree::OnDefNotify(RingBaseWnd*,RINGPARAMS& param)
{
	switch(param.lpnmhdr->code)
	{
		case TVN_SELCHANGED:
			return OnSelectChanged(param);		
		case TVN_ITEMEXPANDING:
			return OnItemExpanding(param);
		default:
			break;
   }
   return -1;
}

LPCTSTR RingDirTree::GetSelFolderName(BOOL bRootNoSlash/*=FALSE*/)
{
	if(bRootNoSlash)
	{
		int nLen = strlen(m_szFolder) - 1;
		if(nLen > 0 && m_szFolder[nLen] == '\\')
			m_szFolder[nLen] = '\0';
	}
	return m_szFolder;
}

LRESULT RingDirTree::OnSelectChanged(RINGPARAMS& param)
{
	NM_TREEVIEW *pnmtv = (NM_TREEVIEW*)param.lParam;
   LPTVITEMDATA lptvid;
   
	lptvid = (LPTVITEMDATA)pnmtv->itemNew.lParam;
	memset(m_szFolder,0,MAX_PATH);
	GetName(lptvid->lpsfParent,lptvid->lpi,SHGDN_FORPARSING,m_szFolder);
	
	
/*	
	if(m_szFolder[1]!=':' || m_szFolder[2]!='\\')
	{
		GetWindowsDirectory(m_szFolder,MAX_PATH);
		strcat(m_szFolder,"\\desktop\0");
		Select(GetRoot());
	}
*/
	return 0;
}

LRESULT RingDirTree::OnItemExpanding(RINGPARAMS& param)
{
	NM_TREEVIEW *pnmtv = (NM_TREEVIEW*)param.lParam;
   LPTVITEMDATA lptvid;
   HRESULT hr;
   LPSHELLFOLDER lpsf2 = NULL;

	if((pnmtv->itemNew.state & TVIS_EXPANDEDONCE))
		return 0;
	
	lptvid = (LPTVITEMDATA)pnmtv->itemNew.lParam;
	hr = lptvid->lpsfParent->BindToObject(lptvid->lpi,0,IID_IShellFolder,(LPVOID*)&lpsf2);
	
	if(SUCCEEDED(hr))
		FillTreeView(lpsf2,lptvid->lpifq,pnmtv->itemNew.hItem);
	
	//SortChildren(pnmtv->itemNew.hItem,SortCBProc);	
	return FALSE;
}

void RingDirTree::FillTreeView(LPSHELLFOLDER lpsf,LPITEMIDLIST lpifq,HTREEITEM hParent)
{
	TV_ITEM         tvi;                          // TreeView Item.
	TV_INSERTSTRUCT tvins;                        // TreeView Insert Struct.
	HTREEITEM       hPrev = NULL;                 // Previous Item Added.
	//LPSHELLFOLDER   lpsf2 = 0;
	LPENUMIDLIST    lpe = 0;
	LPITEMIDLIST    lpi = 0,lpifqThisItem;
	LPTVITEMDATA    lptvid = 0;
	LPMALLOC        lpMalloc = NULL;
	ULONG           ulFetched;
	HRESULT         hr;
	char            szBuff[MAX_PATH];
	HWND            hwnd = GetParent();
	ULONG				 ulAttrs;

	hr=SHGetMalloc(&lpMalloc);
	if(FAILED(hr))
		return;

	SetCursor(LoadCursor(NULL,IDC_WAIT));

	hr = lpsf->EnumObjects(hwnd,
									SHCONTF_FOLDERS|SHCONTF_NONFOLDERS|SHCONTF_INCLUDEHIDDEN,
									&lpe);
	
	if(SUCCEEDED(hr))
	{
		while (S_OK == lpe->Next(1,&lpi,&ulFetched))
		{
			ulAttrs = SFGAO_HASSUBFOLDER|SFGAO_FOLDER;
			
			lpsf->GetAttributesOf(1,(LPCITEMIDLIST*)&lpi,&ulAttrs);
			
			if(ulAttrs & (SFGAO_HASSUBFOLDER | SFGAO_FOLDER))
			{
				if(ulAttrs & SFGAO_FOLDER)
				{
					tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
					
					if(ulAttrs & SFGAO_HASSUBFOLDER)
					{
						tvi.cChildren=1;
						tvi.mask |= TVIF_CHILDREN;
					}
					
					lptvid = (LPTVITEMDATA)lpMalloc->Alloc(sizeof(TVITEMDATA));
					if(lptvid && GetName(lpsf,lpi,SHGDN_NORMAL,szBuff))
					{
						tvi.pszText    = szBuff;
						tvi.cchTextMax = MAX_PATH;
					
						lpifqThisItem = ConcatPidls(lpifq,lpi);					
						lptvid->lpi = CopyITEMID(lpMalloc,lpi);
					
						GetNormalAndSelectedIcons(lpifqThisItem,&tvi) ;
						
						lptvid->lpsfParent = lpsf;    //Store the parent folders SF
						lpsf->AddRef() ;
						
						if(hParent==TVI_ROOT)
							lptvid->lpifq = ConcatPidls(lpifq,lpi);
						else
							lptvid->lpifq = GetFullyQualPidl(lpsf,lpi);
						
						tvi.lParam = (LPARAM)lptvid;
						
						tvins.item = tvi;
						tvins.hInsertAfter = hPrev;
						tvins.hParent = hParent;
						
						hPrev = TreeView_InsertItem(m_hWnd,&tvins);
					}
					else
						break;
				}				
            lpMalloc->Free(lpifqThisItem) ;
            lpifqThisItem = 0;
			}
			
         lpMalloc->Free(lpi);  //Finally, free the pidl that the shell gave us...
         lpi=0;
		}
	}
	
   SetCursor(LoadCursor(NULL,IDC_ARROW));
	
   if(lpe)
		lpe->Release() ;
	
   if(lpi && lpMalloc)
		lpMalloc->Free(lpi);

   if(lpifqThisItem && lpMalloc)
		lpMalloc->Free(lpifqThisItem);
	
   if(lpMalloc)
		lpMalloc->Release();
}

LPITEMIDLIST RingDirTree::ConcatPidls(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)
{
   LPITEMIDLIST pidlNew;
   UINT cb1;
   UINT cb2;

   if(pidl1)  //May be NULL
      cb1 = GetSize(pidl1) - sizeof(pidl1->mkid.cb);
   else
      cb1 = 0;

   cb2 = GetSize(pidl2);

   pidlNew = CreateIDList(cb1 + cb2);
   if(pidlNew)
   {
      if(pidl1)
         memcpy(pidlNew,pidl1,cb1);
      memcpy(((LPSTR)pidlNew) + cb1, pidl2,cb2);
   }
   return pidlNew;
}

LPITEMIDLIST RingDirTree::CopyITEMID(LPMALLOC lpMalloc,LPITEMIDLIST lpi)
{
   LPITEMIDLIST lpiTemp;

   lpiTemp = (LPITEMIDLIST)lpMalloc->Alloc(lpi->mkid.cb+sizeof(lpi->mkid.cb));
   CopyMemory((PVOID)lpiTemp,(CONST VOID *)lpi,lpi->mkid.cb+sizeof(lpi->mkid.cb));

   return lpiTemp;
}

BOOL RingDirTree::GetName(LPSHELLFOLDER lpsf,LPITEMIDLIST lpi,DWORD dwFlags,
								  LPSTR lpFriendlyName)
{
   BOOL bSuccess = TRUE;
   STRRET str;

   if(lpsf->GetDisplayNameOf(lpi,dwFlags,(LPSTRRET)&str)==NOERROR)
   {
      switch (str.uType)
      {
         case STRRET_WSTR:
            WideCharToMultiByte(CP_ACP,                 // CodePage
                                0,		               // dwFlags
                                str.pOleStr,            // lpWideCharStr
                                -1,                     // cchWideChar
                                lpFriendlyName,         // lpMultiByteStr
                                MAX_PATH,//sizeof(lpFriendlyName), // cchMultiByte,
                                NULL,                   // lpDefaultChar,
                                NULL);                  // lpUsedDefaultChar
             break;
         case STRRET_OFFSET:
             lstrcpy(lpFriendlyName,(LPSTR)lpi+str.uOffset);
             break;
         case STRRET_CSTR:
             lstrcpy(lpFriendlyName,(LPSTR)str.cStr);
             break;
         default:
             bSuccess = FALSE;
             break;
      }
   }
   else
      bSuccess = FALSE;

   return bSuccess;
}

LPITEMIDLIST RingDirTree::GetFullyQualPidl(LPSHELLFOLDER lpsf,LPITEMIDLIST lpi)
{
   char szBuff[MAX_PATH];
   OLECHAR szOleChar[MAX_PATH];
   LPSHELLFOLDER lpsfDeskTop;
   LPITEMIDLIST  lpifq;
   ULONG ulEaten, ulAttribs;
   HRESULT hr;

   if(!GetName(lpsf,lpi,SHGDN_FORPARSING,szBuff))
      return NULL;

   hr = SHGetDesktopFolder(&lpsfDeskTop);

   if(FAILED(hr))
      return NULL;

   MultiByteToWideChar(CP_ACP,
					   MB_PRECOMPOSED,
					   szBuff,
					   -1,
					   szOleChar,
					   sizeof(szOleChar));

   hr = lpsfDeskTop->ParseDisplayName(NULL,NULL,szOleChar,&ulEaten,&lpifq,&ulAttribs);

   lpsfDeskTop->Release();

   if(FAILED(hr))
      return NULL;

   return lpifq;
}

int RingDirTree::GetIcon(LPITEMIDLIST lpi,UINT uFlags)
{
   SHFILEINFO sfi;

   SHGetFileInfo((LPCSTR)lpi,
                 0,
                 &sfi,
                 sizeof(SHFILEINFO),
                 uFlags);

   return sfi.iIcon;
}

HICON RingDirTree::GetFileIcon(LPSTR lpi)
{
   SHFILEINFO sfi;

   SHGetFileInfo((LPCSTR)lpi,
                 0,
                 &sfi,
                 sizeof(SHFILEINFO),
                 SHGFI_ICON);

   return sfi.hIcon;
}

void RingDirTree::GetNormalAndSelectedIcons(LPITEMIDLIST lpifq,LPTV_ITEM lptvitem)
{
   lptvitem->iImage = GetIcon(lpifq,SHGFI_PIDL |
                              SHGFI_SYSICONINDEX |
                              SHGFI_SMALLICON);

   lptvitem->iSelectedImage = GetIcon(lpifq,SHGFI_PIDL |
                                      SHGFI_SYSICONINDEX |
                                      SHGFI_SMALLICON |
                                      SHGFI_OPENICON);
}

UINT RingDirTree::GetSize(LPCITEMIDLIST pidl)
{
	UINT cbTotal = 0;
	if(pidl)
	{
		cbTotal += sizeof(pidl->mkid.cb);
		while(pidl->mkid.cb)
		{
			cbTotal += pidl->mkid.cb;
			pidl = Next(pidl);
		}
	}	
	return cbTotal;
}

LPITEMIDLIST RingDirTree::Next(LPCITEMIDLIST pidl)
{
   LPSTR lpMem = (LPSTR)pidl;
	
   lpMem += pidl->mkid.cb;
	
   return (LPITEMIDLIST)lpMem;
}

LPITEMIDLIST RingDirTree::CreateIDList(UINT cbSize)
{
	LPMALLOC lpMalloc;
	HRESULT  hr;
	LPITEMIDLIST pidl=NULL;
	
	hr = SHGetMalloc(&lpMalloc);
	
	if(FAILED(hr))
		return NULL;
	
	pidl = (LPITEMIDLIST)lpMalloc->Alloc(cbSize);
	
	if(pidl)
		memset(pidl,0,cbSize);      // zero-init for external task   alloc
	
	if(lpMalloc)
		lpMalloc->Release();
	
	return pidl;
}